import { Module, OnModuleInit, Logger as NestjsLogger, Inject } from "@nestjs/common";
import { ConfigModule, ConfigService } from "@nestjs/config";
import { UserModule } from "./user/user.module";
import { TestModule } from "./test/test.module";
import { LogsModule } from "./logs/logs.module";
import { AppController } from "./app.controller";
import { AppService } from "./app.service";
import { ResponseInterceptor } from "./interceptors/response.interceptor";
import { HttpExceptionFilter } from "./filters/http-exception.filter";
import { APP_INTERCEPTOR, APP_FILTER, APP_GUARD } from "@nestjs/core";
import * as joi from "joi";
import configuration from "./configuration";
import { TypeOrmModule } from "@nestjs/typeorm";
import { LogLevel, Logs } from "./logs/logs.entity";
import { connectionParams } from "../ormconfig";
import { RolesModule } from "./roles/roles.module";
import { AuthModule } from "./auth/auth.module";
import { AdminGuard } from "./guards/admin.guard";
import { CacheModule, CACHE_MANAGER, Cache } from "@nestjs/cache-manager";
import { MenusModule } from "./menus/menus.module";
import { createKeyv } from "@keyv/redis";
import { RedisModule } from "./redis/redis.module";
import { MailModule } from "./common/mail/mail.module";
import { MongooseModule } from "@nestjs/mongoose";
import { MongoModule } from "./mongo/mongo.module";

@Module({
  imports: [
    // NestJS 配置模块 - 用于管理环境变量和应用配置
    ConfigModule.forRoot({
      // 将配置模块设置为全局模块，所有模块都可以直接使用配置服务，无需重复导入
      isGlobal: true,
      // 根据环境变量 NODE_ENV 动态加载不同的环境配置文件
      // 例如：开发环境加载 .env.development，生产环境加载 .env.production
      // 如果 NODE_ENV 未设置，默认使用 development 环境
      envFilePath: [`.env.${process.env.NODE_ENV || "development"}`],
      // 额外加载基础的 .env 文件作为默认配置
      // 这里使用 dotenv.config() 直接加载 .env 文件，作为配置的补充或备用
      // load: [() => dotenv.config({ path: ".env" })],
      load: [configuration],
      validationSchema: joi.object({
        // 定义环境变量的验证规则
        // 这里定义了 NODE_ENV、PORT、DATABASE_URL、DATABASE_HOST 等环境变量的验证规则
        // 如果环境变量未设置或格式不正确，将抛出错误
        NODE_ENV: joi.string().valid("development", "production").required(),
        PORT: joi.number().default(3000),

        // 数据库相关环境变量验证
        DB_TYPE: joi.string().valid("mysql", "postgres", "sqlite", "mariadb").default("mysql"),
        // 数据库主机地址, 例如：localhost 或 127.0.0.1
        DB_HOST: joi.alternatives().try(joi.string().ip(), joi.string().domain()),
        DB_PORT: joi.number().min(1).max(65535).default(3306),
        DB_USERNAME: joi.string().required(),
        DB_PASSWORD: joi.string().required(),
        DB_DATABASE: joi.string().required(),
        DB_SYNC: joi.boolean().default(false),
        DB_LOGGING: joi.boolean().default(false),
        // 日志级别, 例如：debug、info、warn、error
        LOG_LEVELS: joi
          .string()
          .valid(...Object.values(LogLevel))
          .default("info"),
        // Redis 相关环境变量验证
        REDIS_HOST: joi.string().default("localhost"),
        REDIS_PORT: joi.number().min(1).max(65535).default(6379),
        REDIS_PASSWORD: joi.string().optional(),
        REDIS_URL: joi.string().optional(),
      }),
    }),
    // 使用内存缓存的 CacheModule（不再使用 Redis）
    /*  CacheModule.register({
      isGlobal: true,
      ttl: 10000, // 默认 TTL 为 10 秒
    }), */
    CacheModule.registerAsync({
      inject: [ConfigService],
      isGlobal: true, // 添加这个，让缓存全局可用
      useFactory: async (configService: ConfigService) => {
        const logger = new NestjsLogger("CacheModule");
        const redisHost = configService.get<string>("REDIS_HOST", "localhost");
        const redisPort = configService.get<number>("REDIS_PORT", 6379);
        const redisPassword = configService.get<string>("REDIS_PASSWORD");

        // 构建 Redis URL，显式指定数据库 0（与 RedisModule 保持一致）
        const redisUrl = redisPassword
          ? `redis://:${redisPassword}@${redisHost}:${redisPort}/0`
          : `redis://${redisHost}:${redisPort}/0`;

        logger.log(`CacheModule 正在连接到 Redis: ${redisHost}:${redisPort}/0`);

        try {
          // 创建 keyv 实例，禁用命名空间前缀，这样可以直接访问原始 Redis key
          const keyv = createKeyv(redisUrl, {
            namespace: "", // 禁用命名空间前缀，直接使用原始 key
          });

          // 测试连接：尝试设置和获取一个测试键
          await keyv.set("__cache_test__", "ok", 1000);
          const testValue = await keyv.get("__cache_test__");
          await keyv.delete("__cache_test__");

          if (testValue === "ok") {
            logger.log("✅ CacheModule Redis 连接成功");
          } else {
            logger.warn("⚠️ CacheModule Redis 连接测试失败");
          }

          return {
            stores: [keyv],
            ttl: 3000, // 默认 TTL 为 3 秒
          };
        } catch (error) {
          logger.error(`❌ CacheModule Redis 连接失败: ${error.message}`);
          throw error; // 抛出错误，让应用启动失败，便于发现问题
        }
      },
    }),
    UserModule,
    TestModule,
    LogsModule,
    RolesModule,
    MongooseModule.forRootAsync({
      inject: [ConfigService],
      useFactory: (configService: ConfigService) => {
        const uri = configService.get<string>("mongo.uri");

        if (!uri) {
          throw new Error("MongoDB 连接字符串未配置，请检查配置文件或环境变量");
        }

        return {
          uri,
        };
      },
    }),
    TypeOrmModule.forRoot(connectionParams),
    AuthModule,
    MenusModule,
    RedisModule,
    MailModule,
    MongoModule,
  ],
  controllers: [AppController],
  providers: [
    AppService,
    NestjsLogger,
    // 全局响应拦截器
    {
      provide: APP_INTERCEPTOR,
      useClass: ResponseInterceptor,
    },
    // 全局异常过滤器
    {
      provide: APP_FILTER,
      useClass: HttpExceptionFilter,
    },
    // 全局守卫 自动应用到所有路由  可以通过在控制器或方法上使用 @Public() 装饰器来跳过此守卫
    // {
    //   provide: APP_GUARD,
    //   useClass: AdminGuard,
    // },
  ],
})
export class AppModule implements OnModuleInit {
  constructor(
    private readonly configService: ConfigService,
    @Inject(CACHE_MANAGER) private cacheManager: Cache, // 注入缓存管理器
  ) {}

  /**
   * 模块初始化
   */
  async onModuleInit() {
    const logger = new NestjsLogger("AppModule");

    // 再次验证缓存连接
    try {
      await this.cacheManager.set("__app_init_test__", "ok", 1000);
      const testValue = await this.cacheManager.get("__app_init_test__");
      await this.cacheManager.del("__app_init_test__");

      if (testValue === "ok") {
        logger.log("✅ AppModule 初始化完成 - 缓存连接正常");
      } else {
        logger.warn("⚠️ AppModule 初始化完成 - 但缓存连接异常");
      }
    } catch (error) {
      logger.error(`❌ AppModule 初始化时缓存连接失败: ${error.message}`);
    }
  }
}
